/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tewi.jeeunit.config;

import pl.tewi.jeeunit.controllers.BaseApplicationAssembler;
import pl.tewi.jeeunit.controllers.ApplicationAssembler;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.glassfish.embeddable.archive.ScatteredArchive;
import org.glassfish.embeddable.archive.ScatteredEnterpriseArchive;
import pl.tewi.jeeunit.exceptions.ApplicationDeploymentException;
import pl.tewi.jeeunit.exceptions.GeneralFrameworkException;
import pl.tewi.jeeunit.types.ApplicationDesc;
import pl.tewi.jeeunit.types.ModuleDesc;

/**
 * Komponent buduje aplikacje do wdrożenia na serwerze Glassfish
 * @author Marcin Kwapisz
 */
public class GlassfishApplicationAssembler extends BaseApplicationAssembler implements ApplicationAssembler {

    /**
     * Może zawierać dowolną liczbę archiwum war i jar.
     * Jeżeli w adnotacji Application określono typ aplikacji jako {@link ApplicationType.EAR}
     * to muszą być zawarte w niej moduły
     * @param applicationDesc opis aplikacji w postaci {@link ApplicationDesc}
     * @return obietkt {@link ScatteredEnterpriseArchive} reprezentujący zbudowane archiwum
     * @throws ApplicationDeploymentException błąd tworzenia archiwum aplikacyjnego ear
     */
    @Override
    protected final Object buildEAR(final ApplicationDesc applicationDesc) throws ApplicationDeploymentException {
        ScatteredEnterpriseArchive ear = new ScatteredEnterpriseArchive(applicationDesc.getName());
        ScatteredArchive arch = null;
        try {
            for (ModuleDesc moduleDesc : applicationDesc.getModules()) {
                switch (moduleDesc.getModuleType()) {
                    case JAR:
                        arch = (ScatteredArchive) buildJAR(moduleDesc.getName(), moduleDesc.getModulePath(), moduleDesc.getDescriptors());
                        break;
                    case WAR:
                        arch = (ScatteredArchive) buildWAR(moduleDesc.getName(), moduleDesc.getModulePath());
                        break;
                    default:
                        throw new ApplicationDeploymentException(ApplicationDeploymentException.BUILD_EAR_FAILED);
                }
                ear.addArchive(arch.toURI());
            }
            //dodaj deskryptory instalacyjne dla aplikacji ear
            for (String descriptor : applicationDesc.getDescriptors()) {
                arch.addMetadata(new File(descriptor));
            }
        } catch (IOException ex) {
            throw new ApplicationDeploymentException(ApplicationDeploymentException.BUILD_EAR_FAILED, ex);
        }
        return ear;
    }

    /**
     * Dodaje deskryptor instalacyjny do aplikacji
     * @param arch obiekt reprezentujący archiwum aplikacji
     * @param descriptors lista ścieżek do deskryptorów instalacyjnych
     * @throws IOException 
     */
    private void addDeploymentDescriptors(final ScatteredArchive arch, final List<String> descriptors) throws IOException {
        for (String descriptor : descriptors) {
            arch.addMetadata(new File(descriptor));
        }
    }

    /**
     * Archiwum z komponentami EJB. Jezeli okreśono aplikację jako {@link ApplicationType.JAR}
     * to nie może ona zawierać modułów
     * @param appName nazwa aplikacji
     * @param appPath ścieżka do aplikacji
     * @param descriptors lista ścieżek do deskryptorów instalacyjnych
     * @return obiekt {@link ScatteredArchive} reprezentujący archiwum aplikacyjne typu JAR
     * @throws ApplicationDeploymentException błąd tworzenia archiwum jar
     */
    @Override
    protected final Object buildJAR(final String appName, final String appPath, final List<String> descriptors) throws ApplicationDeploymentException {
        try {
            ScatteredArchive jar = new ScatteredArchive(appName, ScatteredArchive.Type.JAR, new File(appPath));
            addDeploymentDescriptors(jar, descriptors);
            return jar;
        } catch (IOException ex) {
            throw new ApplicationDeploymentException(ApplicationDeploymentException.BUILD_JAR_FAILED, ex);
        }
    }

    /**
     * Archiwum może zawierać jar z komponentami EJB. Jeżeli adnotacja Application
     * jest typu {@link ApplicationType.WAR} to może zawierać moduły typu 
     * {@link ApplicationType.JAR} [0..N)
     * @param applicationDesc 
     * @return obiekt {@link ScatteredArchive} reprezentujący archiwum aplikacyjne typu JAR
     */
    @Override
    protected final Object buildWAR(final ApplicationDesc applicationDesc) throws ApplicationDeploymentException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    
    /**
     * Buduje archiwum typu WAR do umieszczenia w archiwum typu EAR
     * @param appName nazwa aplikacji
     * @param appPath ścieżka do aplikacji
     * @return obiekt {@link ScatteredArchive} reprezentujący archiwum apliakcji Web
     * @throws ApplicationDeploymentException błąd w tworzeniu archiwum aplikacji
     */
    @Override
    protected final Object buildWAR(final String appName, final String appPath) throws ApplicationDeploymentException {
        try {
            ScatteredArchive war = new ScatteredArchive(appName, ScatteredArchive.Type.WAR, new File(appPath));
            return war;
        } catch (IOException ex) {
            throw new ApplicationDeploymentException(ApplicationDeploymentException.BUILD_JAR_FAILED, ex);
        }
    }

    /**
     * <p>Metoda sprawdza poprawność opisu wdrażanej aplikacji poprzez wywołanie 
     * metody {@link BaseApplicationAssembler#validateApplicationConfiguration(pl.tewi.jeeunit.types.ApplicationDesc) }.
     * Domyślnie metoda ta zwraca true. Jeżeli są konieczne specjalne wymagania to 
     * należy ją nadpisać.</p>
     * Następnie na podstawie zweryfikowanego opisu aplikacji budowana jest 
     * wersja do wdrożenia na serwer aplikacyjny
     * 
     * @param applicationDesc opis aplikacji w postaci {@link ApplicationDesc}
     * @return obiekt reperezentujacy aplikację do zainstalowania na serwerze aplikacyjnym
     * @throws GeneralFrameworkException 
     */
    @Override
    public final Object build(final ApplicationDesc applicationDesc) throws GeneralFrameworkException {
        if (!validateApplicationConfiguration(applicationDesc)) {
            throw new ApplicationDeploymentException(ApplicationDeploymentException.INVALID_JEEAPP_CONFIGURATION);
        }
        switch (applicationDesc.getApplicationType()) {
            case EAR:
                return buildEAR(applicationDesc);
            case WAR:
                return buildWAR(applicationDesc);
            case JAR:
                return buildJAR(applicationDesc.getName(), applicationDesc.getApplicationPath(), applicationDesc.getDescriptors());
            default:
                throw new ApplicationDeploymentException(ApplicationDeploymentException.UNSUPPORTED_APP_TYPE);
        }
    }
}
